// 用于在 库模式 中从 .ts(x) 或 .vue 源文件生成类型文件（*.d.ts）的 Vite 插件 
// https://github.com/qmhc/vite-plugin-dts/tree/main
import dts from 'vite-plugin-dts'
// 功能全面且轻量级的命令行参数解析工具
import minimist from 'minimist'
import { fileURLToPath, URL } from 'node:url'
import { resolve } from 'path'
import { defineConfig } from 'vite'
import type { BuildEnvironmentOptions } from 'vite'
import vue from '@vitejs/plugin-vue'
import VueDevTools from 'vite-plugin-vue-devtools'
import tailwindcss from '@tailwindcss/vite'
import Components from 'unplugin-vue-components/vite'
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';

const { _: args } = minimist(process.argv.slice(2))
const dir = args[1] ? args[1].split('=')[1] : undefined

const buildDistOptions = {
    emptyOutDir: false,
    copyPublicDir: false,
    lib: {
        /*
            es: 将 bundle 保留为 ES 模块文件，适用于其他打包工具，以及支持 <script type=module> 标签的浏览器
            umd: 通用模块定义规范，同时支持 amd，cjs 和 iife
            iife: 自执行函数，适用于 <script> 标签（如果你想为你的应用程序创建 bundle，那么你可能会使用它）。
                  表示“自执行 函数表达式”
        */
        formats: ['es', 'umd'],
        // 构建为库。如果指定了 build.lib，build.cssCodeSplit 会默认为 false。
        // __dirname的值是vite.config.ts文件所在目录
        entry: resolve(__dirname, 'components', 'index.ts'),  // entry是必需的，因为库不能使用HTML作为入口。
        name: 'naiveplus', // 暴露的全局变量
        fileName: 'index', // 输出的包文件名，默认是package.json的name选项
        cssFileName: "style"
    },
    rollupOptions: {
        // 自定义底层的Rollup打包配置
        // https://rollupjs.org/configuration-options/
        // 确保外部化处理那些你不想打包进库的依赖
        external: [
            'vue',
            'naive-ui',
            '@tailwindcss/vite',
            '@vicons/antd',
            'pinia',
            'less',
            'less-loader',
            'vue-router',
            'element-resize-detector',
            'vuedraggable'
        ],
        // 当创建 iife 或 umd 格式的 bundle 时，你需要通过 output.globals 选项提供全局变量名，以替换掉外部引入。
        output: {
            name: 'naiveplus',
            //format: 'es', // 默认es，可选 'amd' 'cjs' 'es' 'iife' 'umd' 'system'
            exports: 'named', // https://rollupjs.org/configuration-options/#output-exports
            // 在大多数情况下，该选项值为 false 将避免 Rollup 生成多余代码的 getters，因此在很多情况下，可以使代码兼容 IE8。
            // 默认 true，当该选项的值为 false 时，Rollup 不会为外部依赖生成支持动态绑定的代码，而是假定外部依赖永远不会改变。
            // 这使得 Rollup 会生成更多优化代码。请注意，当外部依赖存在循环引用时，该选项值为 false 可能会引起问题。
            externalLiveBindings: false,
            // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
            globals: {
                vue: 'Vue',
                naiveui: 'naive-ui',
                antd: '@vicons/antd',
            }
        }
    },
    // 启用/禁用 CSS 代码拆分。当启用时，在异步 chunk 中导入的 CSS 将内联到异步 chunk 本身，并在其被加载时一并获取。
    // 如果禁用，整个项目中的所有 CSS 将被提取到一个 CSS 文件中。
    // 默认 true，如果指定了 build.lib，build.cssCodeSplit 会默认为 false
    cssCodeSplit: false,
    // boolean | 'esbuild' | 'lightningcss'
    // 默认: 与 build.minify 一致，允许用户覆盖 CSS 最小化压缩的配置，而不是使用默认的 build.minify
    // cssMinify: 'esbuild',
    // 默认 true，启用/禁用 gzip 压缩大小报告。压缩大型输出文件可能会很慢，因此禁用该功能可能会提高大型项目的构建性能。
    // reportCompressedSize: true,
    // 默认 500，规定触发警告的 chunk 大小，单位kbs
    chunkSizeWarningLimit: 1000,
    // boolean | 'inline' | 'hidden'，构建后是否生成 source map 文件。默认 false
    // sourcemap: false
}

const buildESAndLibOptions = {
    // 若 outDir 在 root 目录下，则为 true。默认情况下，若 outDir 在 root 目录下，则 Vite 会在构建时清空该目录。
    // 若 outDir 在根目录之外则会抛出一个警告避免意外删除掉重要的文件。
    // emptyOutDir: true, 
    // 默认情况下，Vite 会在构建阶段将 publicDir 目录中的所有文件复制到 outDir 目录中。
    copyPublicDir: false,
    lib: {
        // 构建为库。如果指定了 build.lib，build.cssCodeSplit 会默认为 false。
        // 或 'components/index.ts'
        entry: resolve(__dirname, 'components', 'index.ts')
    },
    rollupOptions: {
        // 自定义底层的 Rollup 打包配置
        plugins: [],
        // https://cn.rollupjs.org/configuration-options
        // 确保外部化处理那些你不想打包进库的依赖（作为外部依赖）
        external: [
            'vue',
            'naive-ui',
            '@tailwindcss/vite',
            '@vicons/antd',
            'pinia',
            'less',
            'less-loader',
            'vue-router',
            'element-resize-detector',
            'vuedraggable'
        ],
        // 'components/index.ts'
        input: resolve(__dirname, 'components', 'index.ts'),
        output: [
            // https://cn.rollupjs.org/javascript-api/#outputoptions-object
            {
                // 指定所有生成的 chunk 被放置在哪个目录中
                dir: 'es',
                // 指定生成的 bundle 的格式
                format: 'es',
                // 默认：'[name].js'，类型：string | ((chunkInfo: PreRenderedChunk) => string)
                entryFileNames: '[name].js',
                // 指定导出模式 named – 适用于使用命名导出的情况
                exports: 'named',
                // 将使用原始模块名作为文件名，为所有模块创建单独的 chunk，而不是创建尽可能少的 chunk
                preserveModules: true,
                // 确保输入的模块会输出到 es 目录下，而不是在 es/components 下
                preserveModulesRoot: 'components'
            },
            {
                dir: 'lib',
                format: 'cjs',
                entryFileNames: '[name].cjs',
                exports: 'named',
                preserveModules: true,
                preserveModulesRoot: 'components'
            }
        ]
    },
    // 启用/禁用 CSS 代码拆分。当启用时，在异步 chunk 中导入的 CSS 将内联到异步 chunk 本身，并在其被加载时一并获取。
    // 如果禁用，整个项目中的所有 CSS 将被提取到一个 CSS 文件中。
    // 默认 true，如果指定了 build.lib，build.cssCodeSplit 会默认为 false
    cssCodeSplit: true
}

const dtsOptions = {
    // 指定输出目录，默认为 Vite 配置的 'build.outDir'，使用 Rollup 时为 tsconfig.json 的 `outDir`
    outDir: ['es', 'lib'],
    tsconfigPath: './tsconfig.dts.json',
    // 是否将 '.vue.d.ts' 文件名转换为 '.d.ts'，默认 false
    cleanVueFileName: true,
    // 是否生成类型入口文件，默认 false；当为 `true` 时会基于 package.json 的 `types` 字段生成，或者 `${outDir}/index.d.ts`
    insertTypesEntry: false,
    // 是否将发出的类型文件打包进单个文件，默认 false
    rollupTypes: false,
    // 是否将源码里的 .d.ts 文件复制到 `outDir`，默认 false
    copyDtsFiles: false,
    // 使用自定义函数来控制每个文件的输出路径
    beforeWriteFile: (filePath: string, content: string) => {
        // console.log('filePath', filePath)
        // 默认生成的文件路径 filePath: es/components/button/index.d.ts
        // 各个组件需要的文件路径 componentPath: es/button/index.d.ts
        // [^/]+: 匹配一个或多个除了 / 之外的任何单个字符
        let targetPath: string
        // es/components/button/index.d.ts 转换为 es/button/index.d.ts
        targetPath = filePath.replace(/es\/components\/([^/]+)\/index\.d\.ts$/, 'es/$1/index.d.ts')
        if (filePath === targetPath) { // 说明文件路径未被匹配，没有任何变动
            // 将 es/components/button/Button.d.ts 转换为 es/button/Button.d.ts
            targetPath = filePath.replace(/es\/components\/([^/]+)\/([^/]+)\.d\.ts$/, 'es/$1/$2.d.ts')
        }
        if (filePath === targetPath) {
            // 将 es/components/components.d.ts 转换为 es/components.d.ts
            // 将 es/components/index.d.ts 转换为 es/index.d.ts
            targetPath = filePath.replace(/es\/components\/([^/]+)\.d\.ts$/, 'es/$1.d.ts')
        }
        if (filePath === targetPath) {
            // 将 es/components/grid/row/index.d.ts 转换为es/grid/row/index.d.ts
            targetPath = filePath.replace(/es\/components\/([^/]+)\/([^/]+)\/index\.d\.ts$/, 'es/$1/$2/index.d.ts')
            if (filePath === targetPath) {
                // 将 es/components/grid/row/Row.d.ts 转换为 es/grid/row/Row.d.ts
                targetPath = filePath.replace(/es\/components\/([^/]+)\/([^/]+)\/([^/]+)\.d\.ts$/, 'es/$1/$2/$3.d.ts')
            }
        }
        return {
            filePath: targetPath,
            content
        }
    }
}


export default defineConfig({
    plugins: [
        tailwindcss(),
        vue(),
        VueDevTools({
            launchEditor: 'cursor'
        }),
        Components({
            resolvers: [NaiveUiResolver()]
        }),
        // 自动生成类型文件
        dts(dtsOptions)
    ],
    resolve: {
        alias: {
            '@': fileURLToPath(new URL('./src', import.meta.url)),
            '#': fileURLToPath(new URL('./types', import.meta.url)),
            'components': fileURLToPath(new URL('./components', import.meta.url)),
            'less': fileURLToPath(new URL('./src/assets/less', import.meta.url))
        }
    },
    css: {
        preprocessorOptions: {
            less: {
                modifyVars: {
                    themeColor: '#1677FF', // #1890FF
                    themeHoverColor: '#4096ff'
                },
                javascriptEnabled: true
            },
        },
    },
    build: (dir === 'dist' ? buildDistOptions : buildESAndLibOptions) as BuildEnvironmentOptions,
    server: {
        host: true, // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址，包括局域网和公网地址。
        port: 9000, // 指定开发服务器端口
        open: true // 开发服务器启动时，自动在浏览器中打开应用程序。当该值为字符串时，它将被用作 URL 的路径名。
    }
})

